fix(apiserver): decide the API server migration from live cluster state - #5104
Open
xiumozhan wants to merge 1 commit into
Open
fix(apiserver): decide the API server migration from live cluster state#5104xiumozhan wants to merge 1 commit into
xiumozhan wants to merge 1 commit into
Conversation
On a direct upgrade from the deprecated API server layout, the apiserver controller moved the API server into calico-system and repointed the v3.projectcalico.org APIService at it before the leftover allow-tigera.default-deny policy had been removed. That policy sits in the earlier-evaluated allow-tigera tier and selects all() endpoints, so it denied the moved pod at end-of-tier and the pod never became ready. The aggregated API then stayed down permanently, because removing the policy requires the API server that had just been taken out of service. The controller now decides whether to perform the move by reading live state through an uncached reader, so the decision cannot be made from cached state that is no longer true: only v3.LicenseKey is excluded from the manager cache, so a cached read of a projectcalico.org/v3 object is served from the informer's last known contents even when the aggregated API cannot serve. The v3.projectcalico.org APIService supplies both inputs, and the kube-apiserver serves it directly, so reading it does not depend on the thing being measured. spec.service.namespace says which layout is deployed; the Available condition reports the aggregator's own most recent verdict on whether requests can be served. A migration is pending only while that APIService still points into tigera-system, so an upgrade that has already moved the API server does not wait on a policy that can no longer select the pod. When a migration is pending and the aggregated API can serve, the move waits for the deprecated policy to be removed by the installation controller. When a migration is pending and the aggregated API cannot serve, nothing is applied at all: the trap cannot be confirmed gone and nothing can clear it while the API is down, so moving would only repoint the aggregated API onto a pod that cannot be vouched for. The periodic reconcile already registered in Add() retriggers the decision, and an unrecognised decision holds rather than proceeding, since failing open on this gate is not recoverable. Two unsound tests are removed. The tigera-system namespace fallback treated the namespace's absence as proof the gate had passed; that does not hold on a two-hop upgrade, where the intermediate release deletes the namespace while leaving the policy in place, nor after an administrator deletes the namespace to clear a stuck upgrade. The NoMatch exemption treated a missing RESTMapper mapping as proof the policy was absent, which is not evidence about the policy at all. On the pass that performs the migration the projectcalico.org/v3 NetworkPolicy component is applied before the workload rather than after it, removing the window in which the moved pod runs with no policy of its own. Every other pass keeps the existing order, which exists so that a fresh install is not blocked on an API server that cannot become available until the install has progressed. Refs: EV-6821
xiumozhan
force-pushed
the
EV-6821-apiserver-wait-release-v1.42
branch
from
August 1, 2026 18:08
6585533 to
bc625d2
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Cherry-pick of #5103 to
release-v1.42, which ships the affected release. The load-bearing code is identical to master's; only line offsets differ.Bug fix for EV-6821.
On a direct upgrade from the deprecated API server layout, the apiserver-controller moved the Calico API server into
calico-systemand repointed thev3.projectcalico.orgAPIService at it before the leftoverallow-tigera.default-denypolicy had been removed. That policy sits in the earlier-evaluatedallow-tigeratier and selectsall()endpoints, so it denied the moved pod at end-of-tier, the pod never became ready, and the aggregated API stayed down permanently — removing the policy requires the API server that had just been taken out of service.This replaces the first version of this PR, which gated the move on a single cached read of that policy. The controller now decides from live state read through
mgr.GetAPIReader(), so the decision cannot be made from cached contents that are no longer true: onlyv3.LicenseKeyis excluded from the manager cache, so a cached read of aprojectcalico.org/v3object is served from the informer's last known state even when the aggregated API cannot serve.Both inputs come from the
v3.projectcalico.orgAPIService, which the kube-apiserver serves itself, so reading it does not depend on the thing being measured.spec.service.namespacesays which layout is deployed; theAvailablecondition is the aggregator's own most recent verdict on whether requests can be served. A migration is pending only while that APIService still points intotigera-system, so an upgrade that has already moved the API server does not wait on a policy that can no longer select the pod.Add()retriggers the decision.Two unsound tests are removed. The
tigera-systemnamespace fallback treated the namespace's absence as proof the gate had passed; that does not hold on a two-hop upgrade, where the intermediate release deletes the namespace while leaving the policy in place, nor after an administrator deletes the namespace to clear a stuck upgrade. TheNoMatchexemption treated a missing RESTMapper mapping as proof the policy was absent, which is not evidence about the policy at all.On the pass that performs the migration the
projectcalico.org/v3NetworkPolicy component is applied before the workload rather than after it, removing the window in which the moved pod runs with no policy of its own. Every other pass keeps the existing order, which exists so a fresh install is not blocked on an API server that cannot come up yet.Deliberately not changed.
APIServer.Status.Stateremains a latch. The tiers controller gates tier creation on it throughIsProjectCalicoV3Available, so making it live would stop thecalico-systemtier being created while the move is held, which would stop the installation controller reaching its delete of the trap — a new deadlock caused by the fix.Components affected:
pkg/controller/apiserveronly.Testing
Unit tests cover the decision table, including the two-hop state where the APIService already points at
calico-systemand the deny still exists, which must proceed rather than hold. Reconcile-level tests cover both hold paths, asserting that nocalico-apiserverDeployment is created and the APIService is not repointed. The component ordering is pinned by a test that records real clientCreateorder in both directions.Live-validated twice on fresh CE 3.21.4 clusters upgrading to 3.23.1, exercising both hold branches in sequence in each run: the API server was taken down before the upgrade was applied, the gate held without applying anything while the aggregated API was unreachable, moved to waiting on the deprecated deny once it could serve again, and completed once the installation controller removed it. In both runs
calico-system.apiserver-accesswas created before thecalico-apiserverDeployment. Post-cutover unavailability while the new pod passes its readiness probe was 21 and 33 seconds, and recovered in both cases. Both runs reached the expected end state.Release Note
For PR author
make gen-files— not applicable, no API changes.make gen-versions— not applicable, no version changes.